﻿#include "Mail.h"
#include "MailManager.h"
#include "CenterService.h"
#include "base/core/random.h"

Mail::Mail()
{
	_onlineMailInfoList.clear();
	_offlineMailInfoList.clear();
	_tradingMailInfoList.clear();
	_mailUintMap.clear();
	_onlineMailChange = false;
	_offlineMailChange = false;
	_isLogin = false;
	_isHaveNoRead = false;
}

Mail::~Mail()
{
	g_GetTimerAxis()->KillAllTimer(this);
	_onlineMailInfoList.clear();
	_offlineMailInfoList.clear();
	_tradingMailInfoList.clear();
	_mailUintMap.clear();
	
}

void Mail::Init(CharIDType charId)
{
	_charId = charId;
}

void Mail::SaveData()
{
	//保存在线的玩家数据
	if (_onlineMailChange)
	{
		string strlog = "";
		string strupdate = "";
		SaveMailDBRequest req;
		MailDBInfo* mailDBInfo = req.mutable_info();
		mailDBInfo->set_charid(_charId);
		MailUintIter iter = _mailUintMap.begin();
		for (; iter != _mailUintMap.end(); ++iter)
		{
			MailIDType mailId = iter->second.mailId;
			if (iter->second.type == UNIT_UPDATE) //更新操作的
			{
				bool bFind = false;
				if (_isLogin)  //在线才会查询在线列表
				{
					for (MailInfoIter mailIter = _onlineMailInfoList.begin(); mailIter != _onlineMailInfoList.end(); ++mailIter)
					{
						if (mailId == mailIter->mailhead().mailid())
						{
							if (MAIL_SOURCE_AUCTIONEER == mailIter->source())
							{
								MMOLOG_FMT_INFO("Mail::SaveData..cid:%lu,mailid:%u,content:%s ", _charId, mailId, mailIter->content().c_str());
							}
							char szTmp[50] = { '\0' };
							snprintf(szTmp, sizeof(szTmp) - 1, "%u,", mailIter->mailhead().mailid());
							strupdate += szTmp;

							//
							mailDBInfo->add_data()->CopyFrom((*mailIter));
							bFind = true;
							break;
						}
					}
				}

				if (!bFind)
				{
					for (MailInfoIter mailIterA = _tradingMailInfoList.begin(); mailIterA != _tradingMailInfoList.end(); ++mailIterA)
					{
						if (mailId == mailIterA->mailhead().mailid())
						{
							if (MAIL_SOURCE_AUCTIONEER == mailIterA->source())
							{
								MMOLOG_FMT_INFO("Mail::SaveData..cid:%lu,mailid:%u,content:%s ", _charId, mailId, mailIterA->content().c_str());
							}
							char szTmp[50] = { '\0' };
							snprintf(szTmp, sizeof(szTmp) - 1, "%u,", mailIterA->mailhead().mailid());
							strupdate += szTmp;
							//
							mailDBInfo->add_data()->CopyFrom((*mailIterA));
							bFind = true;
							break;
						}
					}
				}
			}
			else if (iter->second.type == UNIT_DELETE) //删除操作的
			{
				char szTmp[100] = { '\0' };
				snprintf(szTmp, sizeof(szTmp) - 1, " %u, ", mailId);
				strlog += szTmp;
				//
				mailDBInfo->add_deletemailids(mailId);
			}
		}
		LogInfoFmtPrint("Mail::SaveData..cid:%lu , del:%s,update:%s ",_charId, strlog.c_str(),strupdate.c_str());
		//发往DB服保存在线数据
		if (!g_GetCenterService()->SendDataToDBProxy(EMODULE_ID_MAIL, DBPROXY_PROTOCOL_SAVE_MAIL_DATA_REQ, &req))
		{
			MMOLOG_FMT_ERROR("[center] Save Character Online MailInfo SendDataToDBProxy failed cid:%lu ", _charId);
		}

		_onlineMailChange = false;
		_mailUintMap.clear();
	}

	//保存离线数据
	if (_offlineMailChange)
	{
		string stroffline = "";
		SaveOfflineDBRequest req;
		OfflineMailDBInfo* offlineMailDBInfo = req.mutable_info();
		OfflineMailList* offlineMailList = offlineMailDBInfo->mutable_data();
		for (uint32_t i = 0; i < _offlineMailInfoList.size(); i++)
		{
			MailInfo &mailInfo = _offlineMailInfoList[i];
			if (MAIL_SOURCE_AUCTIONEER == mailInfo.source())
			{
				MMOLOG_FMT_INFO("Mail::SaveData..offline cid:%lu,mailid:%u,content:%s ", _charId, mailInfo.mailhead().mailid(), mailInfo.content().c_str());
			}
			//
			char szTmp[100] = { '\0' };
			snprintf(szTmp, sizeof(szTmp) - 1, " %u, ", mailInfo.mailhead().mailid());
			stroffline += szTmp;
			//
			offlineMailList->add_data()->CopyFrom(_offlineMailInfoList[i]);
		}

		offlineMailDBInfo->set_charid(_charId);
		//
		LogInfoFmtPrint("Mail::SaveData..cid:%lu , offline:%s ", _charId, stroffline.c_str());
		//发往DB服保存在线数据
		if (!g_GetCenterService()->SendDataToDBProxy(EMODULE_ID_MAIL, DBPROXY_PROTOCOL_SAVE_OFFLINE_MAIL_DATA_REQ, &req))
		{
			MMOLOG_FMT_ERROR("[center] Save Character Offline MailInfo SendDataToDBProxy failed cid:%lu ", _charId);
		}

		_offlineMailChange = false;
	}

}

void Mail::OnTimer(uint32_t mailId)
{
	for (MailInfoIter mailIterA = _tradingMailInfoList.begin(); mailIterA != _tradingMailInfoList.end(); ++mailIterA)
	{
		MailInfo &mailInfo = (*mailIterA);
		if (mailId == mailInfo.mailhead().mailid())
		{
			g_GetMailMgr()->NdrTradingMail(_charId, mailId);
			break;
		}
	}

}

//服务器启动时加载
bool Mail::LoadTradingMailData(const MailInfo& mailInfo)
{
	MailIDType mailId = mailInfo.mailhead().mailid();
	if (mailId > 0)
	{
		for (MailInfoIter mailIter = _tradingMailInfoList.begin(); mailIter != _tradingMailInfoList.end(); ++mailIter)
		{
			if (mailIter->mailhead().mailid() == mailId)
			{
				MMOLOG_FMT_ERROR("[center] Mail::LoadTradingMailData but mailid:%u is exist charid:%llu", mailId, _charId);
				return false;
			}
		}
		//这里需要设置下是否有附件，因为是否有附件没有存DB,但是前端需要这个字段,这个字段只存内存，不用存DB
		MailHead *mailHead = const_cast<MailHead*>(&mailInfo.mailhead());
		if (nullptr != mailHead)
		{
			mailHead->set_has_attach(g_GetMailMgr()->HasAttach(mailInfo));
		}
		_tradingMailInfoList.push_back(mailInfo);
		return true;
	}

	return false;
}

bool Mail::LoadOfflineMailData(const OfflineMailList& offlineMailList)
{
	for (int i = 0; i < offlineMailList.data_size(); i++)
	{
		const MailInfo& mailInfo = offlineMailList.data(i);
		MailIDType mailId = mailInfo.mailhead().mailid();
		if (mailId > 0)
		{
			//重新计算最大的邮件ID
			g_GetMailMgr()->CalcuMaxMailID(mailId);
			//这里需要设置下是否有附件，因为是否有附件没有存DB,但是前端需要这个字段,这个字段只存内存，不用存DB
			MailHead *mailHead = const_cast<MailHead*>(&mailInfo.mailhead());
			if (nullptr != mailHead)
			{
				mailHead->set_has_attach(g_GetMailMgr()->HasAttach(mailInfo));
			}
			_offlineMailInfoList.push_back(mailInfo);
		}
	}

	return true;
}

bool Mail::InitTradingMail()
{
	MailInfoIter iter = _tradingMailInfoList.begin();
	for (; iter != _tradingMailInfoList.end(); ++iter)
	{
		//检查是否超时了
		MailIDType mailId = iter->mailhead().mailid();

		uint32_t nowTime = Time::Now().sec();
		uint32_t createTime = iter->mailhead().createtime();
		uint32_t leftTime = nowTime - createTime;
		if (leftTime >= MAIL_TRADE_EXIST_TIME) //超过交易邮件随机2-10s时间自动退信自动退信
		{
			int32_t sec = Random(2,10);
			g_GetTimerAxis()->SetTimer(mailId, sec * 1000, this, 1);
		}
		else
		{
			//启动交易邮件定时器
			g_GetTimerAxis()->KillTimer(mailId, this);
			g_GetTimerAxis()->SetTimer(mailId, (MAIL_TRADE_EXIST_TIME - leftTime) * 1000, this, 1);
		}
	}

	return true;
}

bool Mail::StartTradingMailTimer(MailIDType mailId)
{
	g_GetTimerAxis()->KillTimer(mailId, this);

	for (MailInfoIter mailIter = _onlineMailInfoList.begin(); mailIter != _onlineMailInfoList.end(); ++mailIter)
	{
		if (mailIter->mailhead().mailid() == mailId)
		{
			g_GetTimerAxis()->SetTimer(mailId, MAIL_TRADE_EXIST_TIME, this, 1);
			return true;
		}
	}

	MMOLOG_FMT_ERROR("[center] Mail::StartTradingMailTimer mailid:%u charid%llu, but online mail info have no id mail", mailId, _charId);
	return false;
}

bool Mail::CancelTradingMailTimer(MailIDType mailId)
{
	for (MailInfoIter mailIter = _onlineMailInfoList.begin(); mailIter != _onlineMailInfoList.end(); ++mailIter)
	{
		if (mailIter->mailhead().mailid() == mailId)
		{
			g_GetTimerAxis()->KillTimer(mailId, this);
			return true;
		}
	}

	MMOLOG_FMT_ERROR("[center] Mail::CancelTradingMailTimer mailid:%u charid%llu, but online mail info have no id mail", mailId, _charId);
	return false;
}

bool Mail::StartTradeMailTimer(MailIDType mailId)
{
	g_GetTimerAxis()->KillTimer(mailId, this);

	for (MailInfoIter mailIter = _tradingMailInfoList.begin(); mailIter != _tradingMailInfoList.end(); ++mailIter)
	{
		if (mailIter->mailhead().mailid() == mailId)
		{
			g_GetTimerAxis()->SetTimer(mailId, MAIL_TRADE_EXIST_TIME * 1000, this, 1);
			return true;
		}
	}

	LogErrFmtPrint("[center] Mail::StartTradeMailTimer mailid:%u charid%llu, but _tradingMailInfoList have no id mail", mailId, _charId);
	return false;
}
bool Mail::CancelTradeMailTimer(MailIDType mailId)
{
	for (MailInfoIter mailIter = _tradingMailInfoList.begin(); mailIter != _tradingMailInfoList.end(); ++mailIter)
	{
		if (mailIter->mailhead().mailid() == mailId)
		{
			g_GetTimerAxis()->KillTimer(mailId, this);
			return true;
		}
	}

	LogErrFmtPrint("[center] Mail::CancelTradeMailTimer mailid:%u charid%llu, but _tradingMailInfoList have no id mail", mailId, _charId);
	return false;
}

bool Mail::RestartTradeMailTimer(MailIDType mailId)
{
	g_GetTimerAxis()->KillTimer(mailId, this);

	for (MailInfoIter mailIter = _tradingMailInfoList.begin(); mailIter != _tradingMailInfoList.end(); ++mailIter)
	{
		if (mailIter->mailhead().mailid() == mailId)
		{
			uint32_t createTime = mailIter->mailhead().createtime();
			uint32_t nowTime = Time::Now().sec();
			uint32_t leftTime = nowTime - createTime;
			if (leftTime >= MAIL_TRADE_EXIST_TIME) //如果超时了那么两秒后触发自动退信
			{
				g_GetTimerAxis()->SetTimer(mailId, 2000, this, 1);
			}
			else
			{
				g_GetTimerAxis()->SetTimer(mailId, (MAIL_TRADE_EXIST_TIME - leftTime) * 1000, this, 1);
			}
			return true;
		}
	}

	MMOLOG_FMT_ERROR("[center] Mail::RestartTradeMailTimer mailid:%u charid%llu, but _tradingMailInfoList have no id mail", mailId, _charId);
	return false;
}


bool Mail::RestartTradingMailTimer(MailIDType mailId)
{
	g_GetTimerAxis()->KillTimer(mailId, this);

	for (MailInfoIter mailIter = _onlineMailInfoList.begin(); mailIter != _onlineMailInfoList.end(); ++mailIter)
	{
		if (mailIter->mailhead().mailid() == mailId)
		{
			uint32_t createTime = mailIter->mailhead().createtime();
			uint32_t nowTime = Time::Now().sec();
			uint32_t leftTime = nowTime - createTime;
			if (leftTime >= MAIL_TRADE_EXIST_TIME) //如果超时了那么两秒后触发自动退信
			{
				g_GetTimerAxis()->SetTimer(mailId, 2000, this, 1);
			}
			else
			{
				g_GetTimerAxis()->SetTimer(mailId, (MAIL_TRADE_EXIST_TIME - leftTime), this, 1);
			}
			return true;
		}
	}

	MMOLOG_FMT_ERROR("[center] Mail::RestartTradingMailTimer mailid:%u charid%llu, but online mail info have no id mail", mailId, _charId);
	return false;
}

Mail::MailInfoList& Mail::GetMailData()
{
	return _onlineMailInfoList;
}

Mail::MailInfoList& Mail::GetTradeMailData()
{
	return _tradingMailInfoList;
}

void Mail::CacheUpdateMailId(MailIDType mailId, MailUnitType type)
{
	if (type == UNIT_DELETE)
	{
		//check if mailId in
		MailUintIter iter = _mailUintMap.find(mailId);
		if (iter != _mailUintMap.end())
		{
			_mailUintMap.erase(iter);
		}
	}

	MailUnit mailUint;
	mailUint.mailId = mailId;
	mailUint.type = type;
	_mailUintMap[mailId] = mailUint;

	_onlineMailChange = true;
}

void Mail::CacheOfflineMail(MailInfo& mailInfo)
{
	if (_offlineMailInfoList.size() >= MAX_OFFLINE_MAIL)
	{
		//delete the first one
		MailInfoIter mailIter = _offlineMailInfoList.begin();
		if (mailIter != _offlineMailInfoList.end())
		{
			LogDebugFmtPrint("CacheOfflineMail...del mail..mailid:%u,charid:%lu ", mailIter->mailhead().mailid(), _charId);
			_offlineMailInfoList.erase(mailIter);
		}
	}

	MailIDType mailId = mailInfo.mailhead().mailid();

	for (MailInfoIter mailIter = _offlineMailInfoList.begin(); mailIter != _offlineMailInfoList.end();)
	{
		if (mailIter->mailhead().mailid() == mailId)
		{
			LogErrFmtPrint("CacheOfflineMail...del same mail..mailid:%u,charid:%lu ", mailIter->mailhead().mailid(), _charId);

			_offlineMailInfoList.erase(mailIter);
			_offlineMailInfoList.push_back(mailInfo);
			_offlineMailChange = true;
			return;
		}
		else
		{
			++mailIter;
		}
	}

	_offlineMailInfoList.push_back(mailInfo);
	_offlineMailChange = true;
}

bool Mail::OnLogin(const CharacterMailDBResponse& data)
{
	_onlineMailInfoList.clear();
	for (int i = 0; i < data.info_size(); i++)
	{
		const MailInfo& mailInfo = data.info(i);
		const MailHead& mailHead = mailInfo.mailhead();
		//如果是交易邮件那么需要检查是否已经过期了 过期的话进行删除
		if (mailHead.type() == MAIL_TYPE_TRADE)
		{
			//这里是已经领取过的交易邮件
			if (!mailHead.fetch())
			{
				LogErrFmtPrint("[center] Mail::OnLogin.....trade mail not fetched....charid:%lu, mailid:%u ", _charId,mailHead.mailid());
				continue;
			}
		}
		//这里需要设置下是否有附件，因为是否有附件没有存DB,但是前端需要这个字段,这个字段只存内存，不用存DB
		MailHead *pmailHead = const_cast<MailHead*>(&mailHead);
		if (nullptr != pmailHead)
		{
			pmailHead->set_has_attach(g_GetMailMgr()->HasAttach(mailInfo));
		}
		_onlineMailInfoList.push_back(mailInfo);
		if (mailHead.status() == MS_NOT_READ)
		{
			_isHaveNoRead = true;
		}
	}

	//上线后将离线邮件列表的数据保存到在线列表中去
	uint32_t mailSize = GetAllNum() + _offlineMailInfoList.size() ;
	if (mailSize <= MAX_MAIL) //如果小于等于100封上限那么直接将离线邮件数据直接放入到在线列表
	{
		for (uint32_t i = 0; i < _offlineMailInfoList.size(); i++)
		{
			_onlineMailInfoList.push_back(_offlineMailInfoList[i]);

			MailIDType addMailId = _offlineMailInfoList[i].mailhead().mailid();

			CacheUpdateMailId(addMailId, UNIT_UPDATE);
		}
	}
	else //如果大于100封上限那么移除在线邮件数据
	{
		uint32_t deletSize = _offlineMailInfoList.size();
		for (uint32_t i = 1; i <= deletSize; i++)
		{
			MailInfo *pDelMailInfo = FindCanDel();
			if (nullptr != pDelMailInfo)
			{
				bool bDel = false;
				uint32_t delMailId = pDelMailInfo->mailhead().mailid();
				if (MAIL_TYPE_TRADE == pDelMailInfo->mailhead().type())
				{
					//交易邮件
					Mail::MailInfoIter iter = _tradingMailInfoList.begin();
					for (; iter != _tradingMailInfoList.end(); ++iter)
					{
						if (iter->mailhead().mailid() == delMailId)
						{
							CancelTradeMailTimer(delMailId);
							_tradingMailInfoList.erase(iter);
							bDel = true;
							break;
						}
					}
				}
				else
				{
					Mail::MailInfoIter iter = _onlineMailInfoList.begin();
					for (; iter != _onlineMailInfoList.end(); ++iter)
					{
						if (iter->mailhead().mailid() == delMailId)
						{
							_onlineMailInfoList.erase(iter);
							bDel = true;
							break;
						}
					}
				}
				if (bDel)
				{
					CacheUpdateMailId(delMailId, UNIT_DELETE);
				}
			}
		}

		for (uint32_t j = 0; j < deletSize; j++)
		{
			_onlineMailInfoList.push_back(_offlineMailInfoList[j]);

			MailIDType addMailId = _offlineMailInfoList[j].mailhead().mailid();

			CacheUpdateMailId(addMailId, UNIT_UPDATE);
		}
	}

	if (_offlineMailInfoList.size() > 0)
	{
		_offlineMailInfoList.clear();
		_offlineMailChange = true;
	}

	_isLogin = true;
	
	_zoneMailId = data.zonemailid();

	//检查是否有全服邮件
	g_GetMailMgr()->TransZoneMailToCharMail(data.charid(), _zoneMailId);

	return true;
}

bool Mail::OnLogout()
{
	//下线立即保存数据
	SaveData();

	_onlineMailInfoList.clear();
	_isLogin = false;
	_isHaveNoRead = false;

	return true;
}

bool Mail::IsLogin()
{
	return _isLogin;
}

bool Mail::IsHaveNoRead()
{
	return _isHaveNoRead;
}

int32_t	Mail::GetAllNum()
{
	return (int32_t)(_onlineMailInfoList.size() + _tradingMailInfoList.size());
}

MailInfo* Mail::FindCanDel()
{
	MailInfo *pMailInfo = nullptr;
	for (Mail::MailInfoIter mailIter = _onlineMailInfoList.begin(); mailIter != _onlineMailInfoList.end(); ++mailIter)
	{
		if (mailIter->mailhead().attachmentnum() == 0 && mailIter->gold() == 0 &&
			mailIter->bindgold() == 0 && mailIter->diamond() == 0 && mailIter->binddiamond() == 0)
		{
			pMailInfo = &(*mailIter);
			break;
		}
	}
	if (nullptr == pMailInfo)
	{
		//如果没找到的话，从在线列表中和交易列表中找出一封带附件并且时间最早邮件
		
		Mail::MailInfoIter iter = _onlineMailInfoList.begin();
		for (; iter != _onlineMailInfoList.end(); ++iter)
		{
			if (nullptr == pMailInfo)
			{
				pMailInfo = &(*iter);
			}
			else if (pMailInfo->mailhead().createtime() > iter->mailhead().createtime())
			{
				pMailInfo = &(*iter);
			}
		}
		Mail::MailInfoIter iterTrade = _tradingMailInfoList.begin();
		for (; iterTrade != _tradingMailInfoList.end(); ++iterTrade)
		{
			if (nullptr == pMailInfo)
			{
				pMailInfo = &(*iterTrade);
			}
			else if (pMailInfo->mailhead().createtime() > iterTrade->mailhead().createtime())
			{
				pMailInfo = &(*iterTrade);
			}
		}
	}

	return pMailInfo;
}